-- 导航行为

-- 模块定义
local M = 
{
	_base_class = require "components.MovingComponent",
	_class_name = "ai.SteerComponent"
}
setmetatable (M, {__index = _G;});
_ENV = M;

-- 引用模块
local Tools = require ("tools.CommonTools");

-- 方法定义
operation_table = Tools.CreateOperationTable (_base_class);

-- 启动指定的导航行为
function operation_table.EnableBehaviour (self, behaviourName, priority, weight)
	local steerBehaviour, newCreated = self:GetSteerBehaviour (behaviourName, true);
	if (newCreated) then
		self._steerWeights = self._steerWeights + weight;
	else
		self._steerWeights = self._steerWeights + weight - steer_behaviour:GetWeight ();
	end

	steerBehaviour:SetEnabled (true);
	steerBehaviour:SetPriority (priority);
	steerBehaviour:SetWeight (weight);

	-- 添加到列表中，按priority的从大到小
	local steerList = self._steerBehaviours;
	steerList:Rmv (steerBehaviour);

	local rawLength = steerList:count ();
	for index = 1, rawLength do
		local _steerBehaviour = steerList:GetItemAt (index);
		if _steerBehaviour:GetPriority () < priority then
			steerBehaviours:Insert (inex, steerBehaviour);
			break;
		end
	end

	if (rawLength == steerList:Count ()) then
		steerList:Add (steerBehaviour);
	end

end

-- 关闭指定的导航行为
function operation_table.DisableBehaviour (self, behaviourName)
	local steerBehaviour = self:GetSteerBehaviour (behaviourName, false);
	if (steerBehaviour ~= nil) then
		steerBehaviour.SetEnabled (false);
	end
end

-- 根据导航行为确定物体的最终位置和相关的运动属性
function operation_table.Update (self, currentTime, deltaTime)
	local steeringForce = self:CalculateSteerForce (currentTime, deltaTime);
	if (steeringForce:Magnitude () > 0.000001) then 
		local acceleration = steeringForce / self.m_dMass;
		self.m_vVelocity = self.m_vVelocity + acceleration;
		self.m_vVelocity = self.m_vVelocity:ClampMagnitude (self.m_dMaxSpeed);
		self:SetPosition (self:GetPosition () + self.m_vVelocity * deltaTime);

		-- TODO xiewneqi 是否需要将物体位置限定在某一范围内？
	end

end

-- 计算附加在物体上的所有导航行为产生的最终作用力
function operation_table.CalculateSteerForce (self, currentTime, deltaTime)
	local steeringForce = UnityVector3Lib.zero ();
	for index = 1, self._steerBehaviours:Count () do
		local steerBehaviour = self._steerBehaviours:GetItemAt (index);
		if (steerBehaviour:GetEnabled ()) then
			local force = steerBehaviour:Update (currentTime, deltaTime) * steerBehaviour:GetWeight () / self._steerWeights;
			
			-- 对结果力做检测，累加或停止计算
			local magnitudeSoFar = steeringForce:Magnitude ();
			local magnitudeRemain = self.m_dMaxForce - magnitudeSoFar;
			if (magnitudeRemain <= 0) then
				break;
			else
				local magnitudeToAdd = force:Magnitude ();
				if (magnitudeToAdd < magnitudeRemain) then
					steeringForce = steeringForce + force;
				else
					steeringForce = steeringForce + force:Normalized () * magnitudeRemain;
				end
			end

		end 
	end 
	return steeringForce;
end

-- 获取当前实例中使用的导航行为，返回值2表示该行为是否是新创建的
function operation_table.GetSteerBehaviour (self, steerName, createIfNone)
	local steerBehaviours = self._steerBehaviours;
	for index = 1, steerBehaviours:Count () do
		local steerBehaviour = steerBehaviours:GetItemAt (index);
		if (steerBehaviour:GetName () == steerName) then
			return steerBehaviour, false;
		end
	end

	if (~createIfNone) then
		return nil, false;
	end

	if (steer_name == "seek") then
		return require ("ai.SeekBehaviour").NewSeekBehaviour (self), true;
	end
	-- 其它行为

	return nil, false;
end

-- 获取物体执行seek行为时的目标点
function operation_table.GetSeekTargetPos (self)
	-- TODO xiewneqi
	return UnityVector3Lib.zero ();
end

function operation_table.SetSeekTargetPos (self)
	-- TODO xiewneqi
end

-- 构造方法
function NewSteerComponent ()
	local instance = _base_class.NewMovingBehaviour ();
	Tools.PrepareInstance (M, instance);
	
	-- 存储导航行为的集合，key为导航行为的name, value为导航行为对象
	instance._steerBehaviours = require ("collections.List").NewList ();
	instance._steerWeights = 0;

	return instance;
end;

return M;


